// 提取出来的请求类 
class HttpRequest {
	constructor(timeout) {
		this.timeout = timeout || 5000; // 一分钟
	}
	/**
	 * GET|POST 方法 
	 * @param {Object} options 请求参数  
	 */
	request(options) {
		const {
			url,
			data = {},
			method = 'GET',
			header = {},
			baseURL
		} = options;

		return new Promise((resolve, reject) => {
			const requestTask = uni.request({
				url: (baseURL || '') + url,
				data,
				method,
				header,
				timeout: this.timeout,
				success: (res) => {
					resolve(res);
				},
				fail: (error) => {
					reject(error);
				}
			});
			// 超时处理
			setTimeout(() => {
				requestTask.abort();
				reject({
					message: '请求超时',
					code: 401
				});
			}, this.timeout);
		});
	}
}
// 事件处理
class HandlingToDefaultDataToInterceptor {
	/**
	 * 处理请求成功的响应
	 * @param {Object} res 响应对象
	 * 403 是token失效了
	 * 401 只是正常的错误处理
	 */
	// handleResponse(res) {
	// 	this.currentRoute = getCurrentPages()[getCurrentPages().length - 1].route;
	// 	const {
	// 		code,
	// 		message
	// 	} = res.data; 
	// 	if ((code === 403) && (this.currentRoute && !this.currentRoute.includes('pages/auth/Login'))) { 
	// 		this.handleLoginFailure(message);
	// 		throw res.data;
	// 	} else if ((code === 100002) && this.currentRoute !== 'pages/auth/Login') {
	// 		this.handlePhoneUnbound(message);
	// 		throw res.data;
	// 	} else if (code === 401) {
	// 		throw res.data;
	// 	}
	// }
	/**
	 * 处理登录失效
	 * @param {string} message 错误信息
	 */
	handleLoginFailure(message) {
		const self = this.vues();
		// 删除token
		// self.$storage.remove('token');
		this.showModal(
			'登录状态',
			message,
			'重新登录',
			() => {
				uni.reLaunch({
					url: '/pages/auth/login'
				});
			}
		);
		uni.hideLoading();
	}
	/**
	 * 处理未绑定手机
	 * @param {string} message 错误信息
	 */
	handlePhoneUnbound(message) {
		this.showModal(
			'评论异常',
			message,
			'绑定手机',
			() => {
				uni.navigateTo({
					url: "/views/bindingMobile/index"
				});
			},
			'取消'
		)
	}

	/**
	 * 简单的请求失败处理
	 * @param {string|Object} error 错误信息
	 */
	handleError(error) {
		if (error.message) {
			uni.showToast({
				title: error.message,
				icon: 'none',
				duration: 2000
			});
		} else if (this.currentRoute && !this.currentRoute.includes('pages/auth/Login')) {
			this.handleLoginFailure(error.errMsg)
		} else {
			uni.showToast({
				title: 'APP更新了...请联系-管理员',
				icon: 'none'
			});
		}
	}
	/**
	 * 显示提示框
	 * @param {string} title 标题
	 * @param {string} content 内容
	 * @param {string} confirmText 确认按钮文本
	 * @param {function} confirmCallback 确认回调函数
	 * @param {string} cancelText 取消按钮文本
	 * @param {function} cancelCallback 取消回调函数
	 */
	showModal(...option) {
		const [title,
			content,
			confirmText,
			confirmCallback,
			cancelText,
			cancelCallback
		] = option
		uni.showModal({
			title,
			content,
			confirmText,
			success: (c) => {
				if (c.confirm) {
					if (confirmCallback) {
						confirmCallback();
					}
				} else if (c.cancel) {
					if (cancelCallback) {
						cancelCallback();
					}
				}
			}
		});
	}

	/**
	 * 获取默认固定多个 data 属性参数的方法
	 */
	getDefaultData() {
		const defaultData = {
			// platform: process.env.UNI_PLATFORM.toUpperCase(),
			// version: uni.getStorageSync('versionCode'),
			// appid: uni.getStorageSync('appid'),
			// access_token: uni.getStorageSync('token'),
			// 其他默认参数...
			version: 201
		};

		Object.keys(this.defaultData).forEach(key => {
			const value = this.defaultData[key];
			defaultData[key] = typeof value === 'function' ? value() : value;
		});

		return defaultData;
	}

	/**
	 * 添加请求拦截器
	 * @param {Function} interceptor 拦截器函数
	 */
	addRequestInterceptor(interceptor) {
		this.requestInterceptors.push(interceptor);
	}

	/**
	 * 添加响应拦截器
	 * @param {Function} interceptor 拦截器函数
	 */
	addResponseInterceptor(interceptor) {
		this.responseInterceptors.push(interceptor);
	}
}

// 导出的请求方法
class Request extends HandlingToDefaultDataToInterceptor {
	constructor(options) {
		super(options);
		this.baseURLs = options.baseURLs || {};
		this.defaultBaseURL = options.defaultBaseURL || '';
		this.timeout = options.timeout;
		this.cache = new Map();
		this.currentRoute = '';
		this.httpRequest = new HttpRequest(this.timeout);
		this.requestInterceptors = []; // 请求拦截器
		this.responseInterceptors = []; // 响应拦截器
		this.defaultData = options.defaultData; // 默认数据
		this.vues = options.vues;
	}

	/**
	 * GET|POST 方法 
	 * @param {Object} options 请求参数 
	 * @param {string | number} retries 重试次数
	 */
	request(options, retries = 0) {
		let {
			url,
			data = {},
			method = 'GET',
			header = {},
			baseURL,
			cache = false,
			contentType
		} = options;
		const defaultData = this.getDefaultData();
		options.data = {
			...defaultData,
			...data
		};
		if (contentType) {
			header['content-type'] = contentType
		}
		options.header = header;
		// 请求拦截器处理
		for (let i = 0; i < this.requestInterceptors.length; i++) {
			const interceptor = this.requestInterceptors[i];
			if (typeof interceptor === 'function') {
				options = interceptor(options);
			}
		}

		const key = `${method}-${url}-${JSON.stringify(data)}`;
		if (cache && this.cache.has(key)) {
			return Promise.resolve(this.cache.get(key));
		}

		return this.httpRequest.request({
			...options,
			baseURL: this.baseURLs[baseURL] || baseURL || this.defaultBaseURL
		}).then(res => {
			// this.handleResponse(res);
			// 响应拦截器处理
			for (let i = 0; i < this.responseInterceptors.length; i++) {
				const interceptor = this.responseInterceptors[i];
				if (typeof interceptor === 'function') {
					res = interceptor(res);
					break;
				}
			}
			if (cache) {
				this.cache.set(key, res);
			}
			return res;
		}).catch(error => {
			if (retries < options.retries) {
				return this.request(options, retries + 1);
			}
			this.handleError(error);
			throw error;
		});
	}

	/**
	 * GET 方法
	 * @param {string | Object} url 请求地址 | options 请求参数
	 * @param {Object | (string | number)} data 请求参数 |retries 重试次数
	 * @param {string} baseURL 接口基础路径
	 * @param {string} contentType 请求头 Content-Type 属性
	 */
	get(url, data = {}, baseURL = '', contentType = '') {
		const method = 'GET';
		if (typeof url === 'object' && url !== null) {
			return this.request({
				...url,
				baseURL,
				contentType,
				method
			}, data);
		} else if (typeof url === 'string') {
			return this.request({
				url,
				data,
				baseURL,
				contentType,
				method
			});
		}
	}

	/**
	 * POST 方法
	 * @param {string | Object} url 请求地址 | options 请求参数
	 * @param {Object | (string | number)} data 请求参数 |retries 重试次数
	 * @param {string} baseURL 接口基础路径
	 * @param {string} contentType 请求头 Content-Type 属性
	 */
	post(url, data = {}, baseURL = '', contentType = 'application/x-www-form-urlencoded') {
		const method = 'POST';
		if (typeof url === 'object' && url !== null) {
			return this.request({
				...url,
				baseURL,
				contentType,
				method
			}, data);
		} else if (typeof url === 'string') {
			return this.request({
				url,
				data,
				baseURL,
				contentType,
				method
			});
		}
	}

	/**
	 * 上传文件
	 * @param {Object} options - 上传选项
	 * @param {string} options.url - 上传的目标URL
	 * @param {string} options.filePath - 要上传的文件路径
	 * @param {string} [options.name='file'] - 文件对应的 key，开发者在服务器端通过这个 key 可以获取到文件二进制内容
	 * @param {Object} [options.formData={}] - HTTP 请求中其他额外的 form data
	 * @param {Object} [options.header={}] - HTTP 请求 Header
	 * @returns {Promise} - 返回一个 Promise 对象
	 */
	upload(options) {
		const {
			url,
			filePath,
			name = 'file',
			formData = {},
			header = {}
		} = options;

		return new Promise((resolve, reject) => {
			// 调用 uni.uploadFile 方法上传文件
			const uploadTask = uni.uploadFile({
				url,
				filePath,
				name,
				formData,
				header,
				success: (res) => {
					resolve(res); // 上传成功，返回结果
				},
				fail: (error) => {
					reject(error); // 上传失败，返回错误信息
				}
			});
			// 超时处理
			setTimeout(() => {
				uploadTask.abort();
				reject(new Error('请求超时'));
			}, this.timeout);
		});
	}
	// 方法同时发起所有请求，不关心请求的顺序。
	parallel(requests) {
		const promises = requests.map(req => this.request(req));
		return Promise.all(promises);
	}
	// 方法按照请求在数组中的顺序依次发起，保证请求的顺序性
	series(requests) {
		return requests.reduce(
			(promise, req) => promise.then(() => this.request(req)),
			Promise.resolve()
		);
	}
}

export default Request;